package com.sh.d1.gameserver.async;

import com.sh.d1.gameserver.MainThreadProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 异步操作处理器
 */
public final class AsyncOperationProcessor {
    /**
     * 日志对象
     */
    static private final Logger LOGGER = LoggerFactory.getLogger(AsyncOperationProcessor.class);

    /**
     * 单例对象
     */
    static private final AsyncOperationProcessor _instance = new AsyncOperationProcessor();

    /**
     * 线程服务数组
     */
    private final ExecutorService[] _esArray = new ExecutorService[8];


    /**
     * 主线程执行者
     */
    private final Executor _mainThreadExecutor = (cmd)-> {
        MainThreadProcessor.getInstance().process(cmd);
    };

    /**
     * 私有化类默认构造器
     */
    private AsyncOperationProcessor() {
        for (int i = 0; i < _esArray.length; i++) {
            // 线程名称
            final String threadName = "AsyncOperationThread[ " + i +" ]";
            // 创建单线程服务
            _esArray[i] = Executors.newSingleThreadExecutor((r) -> {
                // 创建线程并起个名字
                Thread t = new Thread(r);
                t.setName(threadName);
                return t;
            });
        }
    }

    /**
     * 获取单例对象
     *
     * @return 单例对象
     */
    static public AsyncOperationProcessor getInstance() {
        return _instance;
    }

    /**
     * 处理异步操作
     *
     * @param op 异步操作对象
     */
    public void process(IAsyncOperation op) {
        if (null == op) {
            return;
        }

        process(op.getBindId(), op,op);
    }

    /**
     * 处理异步操作
     * @param bindId
     * @param doAsync
     * @param doFinish
     */
    public void process(int bindId, final IDoAsync doAsync, final IDoFinish doFinish) {
        process(bindId, doAsync,
                _mainThreadExecutor,
                doFinish);
    }
    /**
     * 处理异步操作
     * @param bindId
     * @param doAsync
     */
    public void process(int bindId, final IDoAsync doAsync){
        process(bindId,doAsync,null);
    }

    public void process(int bindId, final IDoAsync doAsync,  final  Executor exec, final IDoFinish doFinish){
        if(null==doAsync) {
            return;
        }

        // 根据绑定 Id 获取线程索引
        bindId = Math.abs(bindId);
        int esIndex = bindId % _esArray.length;

        _esArray[esIndex].submit(() -> {
            try {
                // 执行异步操作
                doAsync.doAsync();
                if (null != exec && null !=doFinish) {
                    // 回到主消息线程继续执行完成逻辑
                    exec.execute(doFinish::doFinish);
                }

            } catch (Exception ex) {
                // 记录错误日志
                LOGGER.error(ex.getMessage(), ex);
            }
        });

    }
}
